package futbol.tacticas.concursantes.Broza;

import futbol.General;
import futbol.tacticas.*;
import futbol.tacticas.concursantes.Tactica;
import java.awt.Color;
import java.awt.Point;
import java.util.Vector;


/**
 *
 * @author Charli
 */
public class Broza implements Tactica{

    Point [] zonasJug = new Point[11];
    Point [] nosotros = new Point[11]; //array con la situacion de nuestros jugadores
    Point [] ellos = new Point[11]; //array con la situacion del contrario
    Integer [] fzaContrarios = new Integer[11]; //array con la fuerza calculada de los contrarios
    Point balonAnt = null;  //situacion anterior del balon
    Point balon = null;	//situacion actual del balon
    double velBal = 0; //velocidad del balon
    double angBal = 0; //angulo del balon
    double distAireBalon = 0; //distancia a recorrer por el balon antes de botar
    int numTurno = 0; //contador del numero de iteraciones, para temas de log y demas

    int zonas[][]={  //centros de zonas asignadas a cada jugador (pto de referencia)
            {-150,0},  //portero 1
            {-40,60},  //lateral dcho 2
            {-40,-60}, //lateral izq 3
            {-80,15},  //central dcho 4
            {-80,-15}, //central izq 5
            {-20,0},   //pivote 6
            {10,40},   //volante dcho 7
            {-10,-40}, //volante izq 8
            {40,60},   //extremos dcho 9
            {40,-60},  //extremo izq 10
            {90,0}    //delantero centro 11
        };
    //zonas asignadas a cada jugador (x,y,dx,dy)
    //(x,y) pto superior izq de la zona (dx) ancho de la zona (dy) alto de la zona
    int limiteZona [][]= {
            {-160,-60,40,120},  //portero 1
            {-160,0,120,100},  //lateral dcho 2
            {-160,-120,120,100}, //lateral izq 3
            {-140,40,100,140},  //central dcho 4
            {-140,-100,100,140}, //central izq 5
            {-80,-100,80,120},   //pivote 6
            {-60,-120,80,120},   //volante dcho 7
            {-60,0,80,120}, //volante izq 8
            {-10,0,80,160},   //extremos dcho 9
            {-10,-120,80,160},  //extremo izq 10
            {80,-120,80,160}     //delantero centro 11
    };

    private int nValores[][]={
        {-150,0,7},   //portero 1
        {-20,60,7},  //lateral dcho 2
        {-20,-60,7}, //lateral izq 3
        {-60,15,7},  //central dcho 4
        {-60,-15,7}, //central izq 5
        {100,30,7},   //interior dcho 6
        {60,5,7},     //medio centro 7
        {100,-30,7},  //interior izq 8
        {160,60,7},   //extremo derecho 9
        {160,-55,7},  //extremo izq 10
        {160,-70,7}    //delantero centro 11
    };

    public String getNombre() {
        return "Broza FC";
    }

    public Color getColor1() {
        return Color.BLUE;
    }

    public Color getColor2() {
        return Color.BLUE;
    }

    public Color getColorNumero() {
        return Color.YELLOW;
    }

    public int getFuerza(int n) {
        return nValores[n][2];
    }

    public int getXInicial(int n) {
        return nValores[n][0];
    }

    public int getYInicial(int n) {
        return nValores[n][1];
    }

    public Vector<Comando> getComandos(SituacionJugadores sj) {
        Vector<Comando> ordenes = new Vector();

        int i; //para los bucles for
        Boolean log = false; //si es true sacaremos el log por la consola

        numTurno++; //actualizamos el numero de turno
        miLog(log,"Turno: " + numTurno);
        
        //pasamos los datos viejos a las variables donse de guardan los valores del turno anterior
        balonAnt = balon;

        //calculamos fuerza de los contrarios solo para las 100 primeras iteraciones
        //(estimamos sera suficiente este tiempo)
        //si es el primer turno inicializamos la fza de los contrarios a 0
        if (numTurno==1) {
           for (int k=0;k<11;k++) {
        	   fzaContrarios[k] = 0;
           }
        }
        if ((numTurno>1)&&(numTurno<100)) {
        	calculaFuerzaJugadoresContrarios(sj.getContrario(), ellos, fzaContrarios, log);
        }

        //recojo datos de situacion
        balon = sj.getBola();
        nosotros = sj.getMisJugadores();
        ellos = sj.getContrario();

        //calculamos velocidad y el angulo del balon
        velBal = velocidadBalon(balon,balonAnt);
        angBal = angulo(balon,balonAnt);


        //calculamos donde va a botar el balon si velocidad del balon >=15
        //o el siguiente punto de parada del balon si velocidad del balon <15
        if (velBal >=15) {
        	distAireBalon = boteBalon(velBal);
        } else {
        	distAireBalon = velBal;
        }
        double tempX = (Math.cos(angBal)*distAireBalon) + balon.getX();
        double tempY = (Math.sin(angBal)*distAireBalon) + balon.getY();
        Point sigBola = new Point ((int)tempX,(int)tempY);


        //PORTERO: si el balon esta cerca va a por el para despejarlo.
        if (enRadioAccion(nosotros[0],balon,10)) {
        	miLog(log,"BALON EN EL PORTERO");
        	ordenes.add(pasarBalon(0,nValores[0][2],sj,ordenes,log)); //si tiene el balon intenta pasarla a un medio o delantero
        } else {
        	if (enRadioAccion(nosotros[0],balon,50)) {
	       		ordenes.add(new ComandoIrA(0,sigBola.getX(),sigBola.getY())); //va a por el balon
	       	} else {
	       		//vuelve a su zona pero siempre encarado al balon
	       		double vertical = zonas[0][1];
	       		if ((sigBola.getY() < 31) && (sigBola.getY() > -31)) {
	       			vertical = sigBola.getY();
	       		}
	       		ordenes.add(new ComandoIrA(0,zonas[0][0],vertical));
	       	}
        }

       	//Movimientos por defecto de los jugadores
       	//Si tienen la bola intentan pasar a un medio o delantero o tiran a puerta si estan a menos de 100 de distancia de porteria.
       	//si hay un contrario cerca lo marcan y en otro caso se van a su zona
        for(i=1;i<11;i++) {
          //TIENE EL BALON
          if (enRadioAccion(nosotros[i],balon,10)) {
          	  miLog(log,"BALON en jugador: " + (i+1));
        	  Point porteriaContraria = new Point (160,0);
        	  if (enRadioAccion(nosotros[i],porteriaContraria,125)) {
          		  ordenes.add(new ComandoTiroAPuerta(i,0)); //TODO desviacion aleatoria del tiro
          	  } else {
          		  ordenes.add(pasarBalon(i,nValores[i][2],sj,ordenes,log)); //intenta pasarla a un medio o delantero
          	  }
          } else {
        	  //NO TIENE EL BALON
        	  //si podemos llegar al pto donde botara la bola vamos a el
        	  double turnos = 1;
        	  if (velBal>15) {turnos = velBal-15+1;}      	  
        	  if (enRadioAccion(nosotros[i],sigBola,(int)((10 - nValores[i][2]) * turnos))){
        		 ordenes.add(new ComandoIrA(i,sigBola.getX(),sigBola.getY())); //va a por el balon  
        	  } else {
            	  //si estamos fuera de nuestra zona la accion es volver a ella
            	  if (fueraZona(i)) {
            		  ordenes.add(new ComandoIrA(i,zonas[i][0],zonas[i][1])); //vuelve a su zona
            	  } else {
                	  //variables para establecer los radios para ir a por el balon y los marcajes
                	  //valores para los defensas
                	  int radioBalon = 70;
                	  int radioMarca = 30;

                	  //valores para los medios y delanteros
                	  if (i>4) {
                		  radioBalon = 80;
                		  radioMarca = 30;
                	  }
                	  if (i==10) { //delantero centro no marca a nadie
                		radioBalon = 60;
                	  	radioMarca = 0;
                	  }

                	  if (enRadioAccion(nosotros[i],sigBola,radioBalon)) {
                		  ordenes.add(new ComandoIrA(i,sigBola.getX(),sigBola.getY())); //va a por el balon
                	  } else {
            		  	  int delant = sj.getContrarioMasCerca(i);
                		  if (enRadioAccion(nosotros[i],ellos[delant],radioMarca)) {
                			  //marca al contrario mas cercano por el lado vertical por donde llega el balon
                			  //y adelantandose a el en el eje horizontal
                			  double mov = 5;
                			  if (sigBola.getY() < ellos[delant].getY()) { mov =  -5; }
                			  ordenes.add(new ComandoIrA(i,ellos[delant].getX() + 5,ellos[delant].getY() + mov));
                		  } else {
                			  ordenes.add(new ComandoIrA(i,zonas[i][0],zonas[i][1])); //vuelve a su zona
                		  }
                	  }
            	  }  
        	  }        	          	
          }
        }

        //para evitar bucles infinitos, el jugador mas cercano al punto donde caera el balon siempre
        //va a por la bola
        int [] jj = sj.getInfoMasCercano(nosotros, sigBola, null, false);
        ordenes.add(new ComandoIrA(jj[0],sigBola.getX(),sigBola.getY()));

    	return ordenes;
    }

    //funcion para encapsular los calculos de distancias y que sean mas sencillos de escribir
    public boolean enRadioAccion(Point jugador, Point coordenada, int distancia) {
    	if (General.getDistancia(jugador.getX(), jugador.getY(), coordenada.getX(), coordenada.getY()) <= distancia ) {
    		return true;
    	}
   		return false;
    }

    //calcula la velocidad actual del balon
    public double velocidadBalon(Point balon, Point balonAnt) {
    	return General.getDistancia(balon.getX(), balon.getY(), balonAnt.getX(), balon.getY())-1;
    }

    //calcula el angulo de movimiento del balon
    public double angulo(Point actual, Point anterior) {
    	return General.getAngulo(actual.getX(), actual.getY(), anterior.getX(), anterior.getY());
    }

    //devuelve la distancia recorrida antes del primer bote del balon dependiendo de velocidad de la bola
    public double boteBalon(double velocidad) {
    	double resul = 0;

    	switch ((int)velocidad) {
    		case 21: resul=126; break;
    		case 20: resul=105; break;
    		case 19: resul=85; break;
    		case 18: resul=66; break;
    		case 17: resul=48; break;
    		case 16: resul=31; break;
    		case 15: resul=15; break;
    		default: resul=0;
    	}
    	return resul;
    }

    //devuelve el numero de turnos que hay hasta el primer bote del balon dependiendo de velocidad de la bola
    public double turnosBote(double velocidad) {
    	double resul = 0;

    	switch ((int)velocidad) {
    		case 21: resul=7; break;
    		case 20: resul=6; break;
    		case 19: resul=5; break;
    		case 18: resul=4; break;
    		case 17: resul=3; break;
    		case 16: resul=2; break;
    		case 15: resul=1; break;
    		default: resul=0;
    	}
    	return resul;
    }

    // Calcula la fuerza de los jugadores contrarios
    public void calculaFuerzaJugadoresContrarios(Point[] contrarios, Point [] contrariosAnt, Integer [] fzaContrarios, boolean log) {
        //calculamos la fuerza de cada jugador contrario
        for(int i = 0; i < 11; i++) {
            // La fuerza la calculamos restando de 10 la distancia recorrida por el jugador entre las dos ultimas iteraciones
            fzaContrarios[i] = 10 - Math.round((int)General.getDistancia(contrarios[i].getX(), contrarios[i].getY(), contrariosAnt[i].getX(), contrariosAnt[i].getY()));
            miLog(log, "Contrario: " + i + " - Fuerza: " + fzaContrarios[i]);
        }
    }

    //calcula el pase a efectuar
    //jug - jugador que tiene la bola (pasador)
    //fza - fuerza del jugador que tiene la bola (pasador)
    public Comando pasarBalon(int jug, int fza, SituacionJugadores sj, Vector<Comando> ordenes, boolean log) {
    	double velJug = 10 - fza;
    	double tempX = 0;
    	double tempY = 0;
    	double distPase = 0; //distancia del balon al receptor
    	double distBote = 0; //distancia al primer bote del balon
    	double tpoBote = 0; //turnos hasta el primer bote el balon
    	double angPase = 0; //angulo de la recta de pase
    	//recorremos solo los medios y delanteros para ver a quien pasamos la bola
    	for (int i=10;i>4;i--)  {

    		miLog(log,"INTENTA PASE " + (jug+1) + " a " + (i+1));

    		distPase = Math.round(General.getDistancia(balon.getX(), balon.getY(), nosotros[i].getX(), nosotros[i].getY()));
    		distBote = boteBalon(fza * 3);
    		tpoBote = turnosBote (fza * 3);
    		angPase = angulo(balon,nosotros[i]);

    		miLog(log,"miramos si llega el receptor. distBote:" + distBote + " distPase:" + distPase + " tpoBote:" + tpoBote);
    		//si en tpoBote turnos llegamos a 9 o menos de donde botara el balon el pase es posible
    		if ( (tpoBote*velJug) >= (distBote-distPase-9) )  {
    			//en la recta de pase entre pasador y receptor buscamos cual sera el pto exacto x
    			//donde botara el balon, para poder buscar el contrario mas cercano a dicho punto
    			//formulas ec recta:  y=mx+b; m=y-yo/x-xo

    	        tempX = (Math.cos(angPase)*distBote) + balon.getX();
    	        tempY = (Math.sin(angPase)*distBote) + balon.getY();

				//miramos si llegan los contrarios
    			Point pBote = new Point((int)tempX,(int)tempY);
    			int [] masCerc = sj.getInfoMasCercano(ellos, pBote, null, false);
    			double velContrarioMasCercano = 6;
    			if (fzaContrarios[masCerc[0]] != 0 ) {
        			velContrarioMasCercano = 10 - fzaContrarios[masCerc[0]];
    			}
    			//si en tpoBote turnos el contrario mas cercano no puede llegar a distancia 10
    			//o menos del pto donde botara la bola el pase es seguro y lo hacemos
    			miLog(log,"miramos si llegan los contrarios. contrarioMasCercano:" + (masCerc[0]+1) + " distanciaMasCercano:" + masCerc[1]);
    			if ((tpoBote*velContrarioMasCercano)<=(masCerc[1]-10) ) {
    	    		miLog(log,"PASE SEGURO de " + (jug+1) + " A " + (i+1));
    				ordenes.add(new ComandoIrA(i,tempX,tempY)); //el receptor va al pto de bote
    	    		return (new ComandoGolpearBola(jug,tempX,tempY)); //hacemos el pase al pto de bote
    			}

    		}
    	}
    	//patadon si no hay pase seguro
    	miLog(log,"PATADON a la bola a 160,0");
    	return (new ComandoGolpearBola(jug,160,0));
    }

    //comprueba si el jugador esta fuera de su zona asignada
    public boolean fueraZona (int jug) {
    	boolean resul = true; //por defecto tomamos el jugador esta fuera de su zona
    	int esquinaX = limiteZona[jug][0];
    	int esquinaY = limiteZona[jug][1];
    	int anchoZona = limiteZona[jug][2];
    	int altoZona = limiteZona[jug][3];
    	int jugX = (int)nosotros[jug].getX();
    	int jugY = (int)nosotros[jug].getY();

    	if ((esquinaX <= jugX) && (jugX <= esquinaX + anchoZona)) {
    		if ( (esquinaY <= jugY) && (jugY <= esquinaY + altoZona)) {
    			resul = false; //jugador dentro de su zona
    		}
    	}
    	return resul;
    }


    public void miLog(Boolean log, String cadena) {
    	if (log) {
    		System.out.println(cadena);
    	}
    }
}

